/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_AVMETA_DATA_H
#define OHOS_AVMETA_DATA_H

/**
 * @addtogroup avsession
 * @{
 *
 * @brief Provides APIs for audio and video (AV) media control.
 *
 * The APIs can be used to create, manage, and control media sessions.
 *
 * @syscap SystemCapability.Multimedia.AVSession.Core
 * @since 9
 * @version 1.0
 */

/**
 * @file avmeta_data.h
 *
 * @brief Declares the APIs for setting, obtaining, and cloning session metadata.
 *
 * @since 9
 * @version 1.0
 */

#include <bitset>
#include <memory>
#include <string>
#include <map>
#include "parcel.h"
#include "avsession_pixel_map.h"

#if !defined(WINDOWS_PLATFORM) and !defined(MAC_PLATFORM) and !defined(IOS_PLATFORM)
#include <malloc.h>
#endif

namespace OHOS::AVSession {
/**
 * @brief Represents a session metadata class that provides APIs for marshalling, unmarshalling, and cloning session metadata.
 */
class AVMetaData : public Parcelable {
public:

    /**
     * @brief A global variable macro that defines the playback duration.
     *
     * @since 9
     * @version 1.0
     */
    static constexpr std::int64_t DURATION_ALWAYS_PLAY = -1;

    /**
     * @brief Enumerates the session metadata items.
     */
    enum {
        /** Asset ID. */
        META_KEY_ASSET_ID = 0,
        /** Title. */
        META_KEY_TITLE = 1,
        /** Artist. */
        META_KEY_ARTIST = 2,
        /** Producer. */
        META_KEY_AUTHOR = 3,
        /** Album. */
        META_KEY_ALBUM = 4,
        /** Lyricist. */
        META_KEY_WRITER = 5,
        /** Composer. */
        META_KEY_COMPOSER = 6,
        /** Track length. */
        META_KEY_DURATION = 7,
        /** Media image. */
        META_KEY_MEDIA_IMAGE = 8,
        /** Media image URI. */
        META_KEY_MEDIA_IMAGE_URI = 9,
        /** Date of publication. */
        META_KEY_PUBLISH_DATE = 10,
        /** Subtitle. */
        META_KEY_SUBTITLE = 11,
        /** Asset description. */
        META_KEY_DESCRIPTION = 12,
        /** Lyrics. */
        META_KEY_LYRIC = 13,
        /** Previous asset ID. */
        META_KEY_PREVIOUS_ASSET_ID = 14,
        /** Next asset ID. */
        META_KEY_NEXT_ASSET_ID = 15,
        /** Invalid value, which is used internally to determine whether session metadata is valid. */
        META_KEY_MAX = 16
    };

    /**
     * @brief Marks the session metadata to be cloned.
     *
     * @since 9
     * @version 1.0
     */
    using MetaMaskType = std::bitset<META_KEY_MAX>;

    /**
     * @brief Default constructor of session metadata.
     * @since 9
     * @version 1.0
     */
    AVMetaData() = default;

    /**
     * @brief Default destructor of session metadata.
     * @since 9
     * @version 1.0
     */
    ~AVMetaData() override
    {
#if !defined(WINDOWS_PLATFORM) and !defined(MAC_PLATFORM) and !defined(IOS_PLATFORM)
#if defined(__BIONIC__)
        mallopt(M_PURGE, 0);
#endif
#endif
    }

    /**
     * @brief Unmarshals session metadata from a {@link Parcel} object.
     *
     * @param data Indicates the pointer to the {@link Parcel} object for unmarshalling.
     * @return Returns the pointer to an {@code AVMetaData} object if the operation is successful; returns a null pointer otherwise.
     * @see Marshalling
     * @since 9
     * @version 1.0
     */
    static AVMetaData *Unmarshalling(Parcel& data);

    /**
     * @brief Marshals session metadata into a {@link Parcel} object.
     *
     * @param data Indicates the pointer to the {@link Parcel} object for marshalling.
     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
     * @see Unmarshalling
     * @since 9
     * @version 1.0
     */
    bool Marshalling(Parcel& data) const override;

    /**
     * @brief Sets an ID for this media asset.
     *
     * @param assetId Indicates the pointer to the asset ID to set, which cannot be null.
     * @see GetAssetId
     * @since 9
     * @version 1.0
     */
    void SetAssetId(const std::string& assetId);

    /**
     * @brief Obtains the ID of this media asset.
     *
     * @return Returns the asset ID.
     * @see SetAssetId
     * @since 9
     * @version 1.0
     */
    std::string GetAssetId() const;

    /**
     * @brief Sets a title for this media asset.
     *
     * @param title Indicates the pointer to the title to set.
     * @see GetTitle
     * @since 9
     * @version 1.0
     */
    void SetTitle(const std::string& title);

    /**
     * @brief Obtains the title of this media asset.
     *
     * @return Returns the title.
     * @see SetTitle
     * @since 9
     * @version 1.0
     */
    std::string GetTitle() const;

    /**
     * @brief Sets an artist name for this media asset.
     *
     * @param artist Indicates the pointer to the artist name to set.
     * @see GetArtist
     * @since 9
     * @version 1.0
     */
    void SetArtist(const std::string& artist);

    /**
     * @brief Obtains the artist name of this media asset.
     *
     * @return Returns the artist name.
     * @see SetArtist
     * @since 9
     * @version 1.0
     */
    std::string GetArtist() const;

    /**
     * @brief Sets a producer name for this media asset.
     *
     * @param author Indicates the pointer to the producer name to set.
     * @see GetAuthor
     * @since 9
     * @version 1.0
     */
    void SetAuthor(const std::string& author);

    /**
     * @brief Obtains the producer name of this media asset.
     *
     * @return Returns the producer name.
     * @see SetAuthor
     * @since 9
     * @version 1.0
     */
    std::string GetAuthor() const;

    /**
     * @brief Sets an album name for this media asset.
     *
     * @param album Indicates the pointer to the album name to set.
     * @see GetAlbum
     * @since 9
     * @version 1.0
     */
    void SetAlbum(const std::string& album);

    /**
     * @brief Obtains the album name of this media asset.
     *
     * @return Returns the album name.
     * @see SetAlbum
     * @since 9
     * @version 1.0
     */
    std::string GetAlbum() const;

    /**
     * @brief Sets a lyricist name for this media asset.
     *
     * @param writer Indicates the pointer to the lyricist name to set.
     * @see GetWriter
     * @since 9
     * @version 1.0
     */
    void SetWriter(const std::string& writer);

    /**
     * @brief Obtains the lyricist name of this media asset.
     *
     * @return Returns the lyricist name.
     * @see SetWriter
     * @since 9
     * @version 1.0
     */
    std::string GetWriter() const;

    /**
     * @brief Sets a composer name for this media asset.
     *
     * @param composer Indicates the pointer to the composer name to set.
     * @see GetComposer
     * @since 9
     * @version 1.0
     */
    void SetComposer(const std::string& composer);

    /**
     * @brief Obtains the composer name of this media asset.
     *
     * @return Returns the composer name.
     * @see SetComposer
     * @since 9
     * @version 1.0
     */
    std::string GetComposer() const;

    /**
     * @brief Sets a length for this media asset.
     *
     * @param duration Indicates the length to set, in ms. The value must be greater than or equal to <b>-1</b>.
     * @see GetDuration
     * @since 9
     * @version 1.0
     */
    void SetDuration(int64_t duration);

    /**
     * @brief Obtains the length of this media asset.
     *
     * @return Returns the length, in ms.
     * @see SetDuration
     * @since 9
     * @version 1.0
     */
    int64_t GetDuration() const;

    /**
     * @brief Sets an image for this media asset.
     *
     * @param mediaImage Indicates the pointer to the image to set, which is an {@link AVSessionPixelMap} object.
     * @see GetMediaImage
     * @since 9
     * @version 1.0
     */
    void SetMediaImage(const std::shared_ptr<AVSessionPixelMap>& mediaImage);

    /**
     * @brief Obtains the image of this media asset.
     *
     * @return Returns the image, which is an {@link AVSessionPixelMap} object.
     * @see SetMediaImage
     * @since 9
     * @version 1.0
     */
    std::shared_ptr<AVSessionPixelMap> GetMediaImage() const;

    /**
     * @brief Sets an image URI for this media asset.
     *
     * @param mediaImageUri Indicates the pointer to the image URI to set.
     * @see GetMediaImageUri
     * @since 9
     * @version 1.0
     */
    void SetMediaImageUri(const std::string& mediaImageUri);

    /**
     * @brief Obtains the image URI of this media asset.
     *
     * @return Returns the image URI.
     * @see SetMediaImageUri
     * @since 9
     * @version 1.0
     */
    std::string GetMediaImageUri() const;

    /**
     * @brief Sets the date when this media asset is published.
     *
     * @param date Sets the date, which is a timestamp, in ms.
     * @see GetPublishDate
     * @since 9
     * @version 1.0
     */
    void SetPublishDate(double date);

    /**
     * @brief Obtains the date when this media asset is published.
     *
     * @param Returns the date, which is a timestamp, in ms.
     * @see SetPublishDate
     * @since 9
     * @version 1.0
     */
    double GetPublishDate() const;

    /**
     * @brief Sets a subtitle for this media asset.
     *
     * @param subTitle Indicates the pointer to the subtitle to set.
     * @see GetSubTitle
     * @since 9
     * @version 1.0
     */
    void SetSubTitle(const std::string& subTitle);

    /**
     * @brief Obtains the subtitle of this media asset.
     *
     * @return Returns the subtitle.
     * @see SetSubTitle
     * @since 9
     * @version 1.0
     */
    std::string GetSubTitle() const;

    /**
     * @brief Sets a description for this media asset.
     *
     * @param description Indicates the pointer to the description to set.
     * @see GetDescription
     * @since 9
     * @version 1.0
     */
    void SetDescription(const std::string& description);

    /**
     * @brief Obtains the description of this media asset.
     *
     * @return Returns the description.
     * @see SetDescription
     * @since 9
     * @version 1.0
     */
    std::string GetDescription() const;

    /**
     * @brief Sets lyrics for this media asset.
     *
     * @param lyric Indicates the pointer to the lyrics to set.
     * @see GetLyric
     * @since 9
     * @version 1.0
     */
    void SetLyric(const std::string& lyric);

    /**
     * @brief Obtains lyrics of this media asset.
     *
     * @return Returns the lyrics.
     * @see SetLyric
     * @since 9
     * @version 1.0
     */
    std::string GetLyric() const;

    /**
     * @brief Sets a previous asset ID for this media asset.
     *
     * @param assetId Indicates the pointer to the previous asset ID to set.
     * @see GetPreviousAssetId
     * @since 9
     * @version 1.0
     */
    void SetPreviousAssetId(const std::string& assetId);

    /**
     * @brief Obtains the previous asset ID of this media asset.
     *
     * @return Returns the previous asset ID.
     * @see SetPreviousAssetId
     * @since 9
     * @version 1.0
     */
    std::string GetPreviousAssetId() const;

    /**
     * @brief Sets a next asset ID for this media asset.
     *
     * @param assetId Indicates the pointer to the next asset ID to set.
     * @see GetNextAssetId
     * @since 9
     * @version 1.0
     */
    void SetNextAssetId(const std::string& assetId);

    /**
     * @brief Obtains the next asset ID for this media asset.
     *
     * @return Returns the next asset ID.
     * @see SetNextAssetId
     * @since 9
     * @version 1.0
     */
    std::string GetNextAssetId() const;

    /**
     * @brief Resets all session metadata items.
     *
     * @since 9
     * @version 1.0
     */
    void Reset();

    /**
     * @brief Obtains the mask.
     *
     * @return Returns the mask, which is a {@link MetaMaskType} object.
     * @since 9
     * @version 1.0
     */
    MetaMaskType GetMetaMask() const;

    /**
     * @brief Clones the metadata item to a {@link metaOut} object based on the metadata mask.
     *
     * @param mask Indicates the pointer to the metadata mask, which is a {@link MetaMaskType} object.
     * @param metaOut Indicates the pointer to an {@link AVMetaData} object that holds the cloned session metadata.
     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
     * @since 9
     * @version 1.0
     */
    bool CopyToByMask(MetaMaskType& mask, AVMetaData& metaOut) const;

    /**
     * @brief Clones the metadata item from {@code metaIn} based on the mask in {@code metaIn}.
     *
     * @param metaIn Indicates the {@link AVMetaData} object from which the session metadata will be cloned.
     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
     * @since 9
     * @version 1.0
     */
    bool CopyFrom(const AVMetaData& metaIn);

    /**
     * @brief Checks the validity of session metadata.
     *
     * @return Returns <b>true</b> if the session metadata is valid; returns <b>false</b> otherwise.
     * @since 9
     * @version 1.0
     */
    bool IsValid() const;
    
    /**
     * @brief Defines a session metadata array, which is used for distributed services to set session attributes.
     *
     * @since 9
     * @version 1.0
     */
    const static inline std::vector<int32_t> localCapability {
        META_KEY_ASSET_ID,
        META_KEY_TITLE,
        META_KEY_ARTIST,
        META_KEY_AUTHOR,
        META_KEY_ALBUM,
        META_KEY_WRITER,
        META_KEY_COMPOSER,
        META_KEY_DURATION,
        META_KEY_MEDIA_IMAGE,
        META_KEY_MEDIA_IMAGE_URI,
        META_KEY_PUBLISH_DATE,
        META_KEY_SUBTITLE,
        META_KEY_DESCRIPTION,
        META_KEY_LYRIC,
        META_KEY_PREVIOUS_ASSET_ID,
        META_KEY_NEXT_ASSET_ID,
    };

private:
    /** Used to record the session metadata mask, which is a {@link MetaMaskType} object. */
    MetaMaskType metaMask_;
    /** Asset ID. */
    std::string assetId_ = "";
    /** Title. */
    std::string title_ = "";
    /** Artist. */
    std::string artist_ = "";
    /** Producer. */
    std::string author_ = "";
    /** Album. */
    std::string album_ = "";
    /** Lyricist. */
    std::string writer_ = "";
    /** Composer. */
    std::string composer_ = "";
    /** Track length. */
    int64_t duration_ = 0;
    /** Media image, which is an {@link AVSessionPixelMap} object. */
    std::shared_ptr<AVSessionPixelMap> mediaImage_ = nullptr;
    /** Media image URI. */
    std::string mediaImageUri_ = "";
    /** Date of publication, which is a timestamp, in ms. */
    double publishDate_ = 0;
    /** Subtitle. */
    std::string subTitle_ = "";
    /** Asset description. */
    std::string description_ = "";
    /** Lyrics. */
    std::string lyric_ = "";
    /** Previous asset ID. */
    std::string previousAssetId_ = "";
    /** Next asset ID. */
    std::string nextAssetId_ = "";

    /**
     * @brief Clones the asset ID from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneAssetId(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the title from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneTitle(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the artist name from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneArtist(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the producer name from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneAuthor(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the album name from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneAlbum(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the lyricist name from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneWriter(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the composer name from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneComposer(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the track length from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneDuration(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the image from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneMediaImage(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the image URI from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneMediaImageUri(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the date of publication from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void ClonePublishData(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the subtitle from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneSubTitle(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the description from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneDescription(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the lyrics from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @since 9
     * @version 1.0
     */
    static void CloneLyric(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the previous asset ID from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @see CloneNextAssetId
     * @since 9
     * @version 1.0
     */
    static void ClonePreviousAssetId(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Clones the next asset ID from the source session metadata to the target session metadata.
     *
     * @param from Indicates the pointer to the source session metadata, which is an {@link AVMetaData} object.
     * @param to Indicates the pointer to the target session metadata, which is an {@link AVMetaData} object.
     * @see ClonePreviousAssetId
     * @since 9
     * @version 1.0
     */
    static void CloneNextAssetId(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Redefines the pointer type of the session metadata clone function.
     *
     * @since 9
     * @version 1.0
     */
    using CloneActionType = void(*)(const AVMetaData& from, AVMetaData& to);

    /**
     * @brief Defines an inline function pointer array to perform the session metadata operation by index.
     *
     * @since 9
     * @version 1.0
     */
    static inline CloneActionType cloneActions[META_KEY_MAX] = {
        [META_KEY_ASSET_ID] = &AVMetaData::CloneAssetId,
        [META_KEY_TITLE] = &AVMetaData::CloneTitle,
        [META_KEY_ARTIST] = &AVMetaData::CloneArtist,
        [META_KEY_AUTHOR] = &AVMetaData::CloneAuthor,
        [META_KEY_ALBUM] = &AVMetaData::CloneAlbum,
        [META_KEY_WRITER] = &AVMetaData::CloneWriter,
        [META_KEY_COMPOSER] = &AVMetaData::CloneComposer,
        [META_KEY_DURATION] = &AVMetaData::CloneDuration,
        [META_KEY_MEDIA_IMAGE] = &AVMetaData::CloneMediaImage,
        [META_KEY_MEDIA_IMAGE_URI] = &AVMetaData::CloneMediaImageUri,
        [META_KEY_PUBLISH_DATE] = &AVMetaData::ClonePublishData,
        [META_KEY_SUBTITLE] = &AVMetaData::CloneSubTitle,
        [META_KEY_DESCRIPTION] = &AVMetaData::CloneDescription,
        [META_KEY_LYRIC] = &AVMetaData::CloneLyric,
        [META_KEY_PREVIOUS_ASSET_ID] = &AVMetaData::ClonePreviousAssetId,
        [META_KEY_NEXT_ASSET_ID] = &AVMetaData::CloneNextAssetId,
    };
};
} // namespace OHOS::AVSession
/** @}*/
#endif // OHOS_AVMETA_DATA_H
